package com.aliyun.heiyu.common.util;

import java.io.IOException;
import java.util.Arrays;

import com.aliyun.heiyu.common.source.PskDao;
import com.aliyun.heiyu.common.source.PskImpl;
import com.aliyun.heiyu.common.source.Psktable;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import com.sgitg.sgcc.sm.SM2Utils;
import com.aliyun.heiyu.common.util.sm.utils.HexEncode;
import com.aliyun.heiyu.common.util.sm.utils.StringUtil;



/**
 * 本类主要提供国密SM2算法 使用样例，
 * 此样例包含国密SM2算法的加密、解密、签名、验签方法的使用；
 *
 * *********注意事项*********
 * 1) 所使用的包名为com.sgitg.sgcc.sm.*;
 * 2) 此算法使用只能依赖bcprov-jdk16-1.46.jar,项目中不能同时含有bouncy castle的其他版本的jar，
 * 		否则使用过程中算法运算会抛出异常
 * 3) 以下SM2Util针对String字符串进行算法操作，
 * 		若项目组需要进行文件加密操作请使用SM2Utils对外方法进行byte数组算法运算处理
 */
public class SM2Util{

    private final static SM2Utils SM2_UTILS  = new SM2Utils();

    //该公钥与私钥不配对
    private static byte[] pkey; // 公钥字节码
    private static byte[] skey; // 私钥字节码

    static {
        PskDao dao = new PskImpl();
        Psktable psk = dao.findOne("1");
        skey = ByteUtils.fromHexString(psk.getSkey());
        pkey = ByteUtils.fromHexString(psk.getPkey());
    }

    /**
     * 国密SM2算法加密方法
     * @param plainText 需要加密的数据
     * @return 返回加密后hex编码字符串
     */
    public static String encryptBySM2(String plainText){
        if(StringUtils.isBlank(plainText)) {
            return plainText;
        }
        //hex编码的公钥进行转换为byte数组
        //byte[] key = Hex.decode(pubKey);
        byte [] cipherByteArray = null;
        try {
            cipherByteArray = SM2_UTILS.SG_SM2EncData(pkey, plainText.getBytes());
        } catch (IOException e) {
            throw new RuntimeException("国密SM2算法加密失败",e);
        }
        //将加密后的byte数组进行hex编码，以String字符形式输出
        return (HexEncode.byteToHex(cipherByteArray));
    }

    /**
     * 国密SM2算法解密方法
     * @param cipherText 加密后的hex编码数据
     * @return 加密后明文数据
     */
    public static String decryptBySM2(String cipherText){
        try {
            if(StringUtils.isBlank(cipherText)) {
                return cipherText;
            }
            //加密后的密文先进行hex解码为byte数组
            byte[] cipher = HexEncode.hexToByte(cipherText);
            //私钥进行hex解码为byte数组
            //byte [] prikey = Hex.decode(priKey);
            byte[] plainByteArray = null;
            try {
                plainByteArray = SM2_UTILS.SG_SM2DecData(skey, cipher);
            } catch (IOException e) {
                throw new RuntimeException("国密SM2算法解密失败",e);
            }
            //解密后进行字符转为字符串形式
            return StringUtil.fromUTF8ByteArray(plainByteArray);
        } catch (Exception e) {
            throw new RuntimeException("国密SM2算法解密失败",e);
        }
    }

    /**
     * 国密SM2算法加密方法
     * @param plainText 需要加密的数据
     * @return 返回加密后hex编码字符串
     */
    public static String encryptToHex(String plainText){
        try {
            return encryptBySM2(plainText);
        } catch (RuntimeException e) {
        }
        return plainText;
    }

    /**
     * 国密SM2算法解密方法
     * @param cipherText 加密后的hex编码数据
     * @return 加密后明文数据
     */
    public final static String decryptToHex(String cipherText){
        try {
            return decryptBySM2(cipherText);
        } catch (RuntimeException e) {
        }
        return cipherText;
    }

    public static String[] generateKeyPairs(){
        byte[] keyPair = SM2_UTILS.SG_generateKeyPair();
        String priKeyHex= (HexEncode.byteToHex(Arrays.copyOfRange(keyPair, 0, 32)));
        String pubKeyHex = (HexEncode.byteToHex(Arrays.copyOfRange(keyPair, 32, 97)));
        return new String[]{priKeyHex,pubKeyHex};
    }
}
